//
// Created by abstergo on 2024/2/11.
//

#ifndef TBS_CPP_POOL_CU
#define TBS_CPP_POOL_CU
#include <base/log.hpp>

template<typename Type>
void Pool<Type>::onRelease(Type *item, tbs::sys_unique_lock &lock) {
  condition_variable_.notify_one();
}

template<typename Type>
size_t Pool<Type>::size()
CONST {
return
pool_size_;
}

template<typename Type>
Type &Pool<Type>::PoolWrapper::value() { return *item; }

template<typename Type>
void Pool<Type>::PoolWrapper::m_release() { _source->release(value()); }

template<typename Type>
Type *Pool<Type>::remake_on_release(Type *old) {
  delete old;
  return new Type();
}

template<typename Type>
bool Pool<Type>::is_reset_on_release() { return _rf != nullptr; }

template<typename Type>
void Pool<Type>::setResetFunction(Pool::reset_func f) { this->_rf = f; }

template<typename Type>
tbs::WrappedGuard <Type> Pool<Type>::acquire() {
  Type *raw = nullptr;
  {
	tbs::sys_unique_lock lock(mutex_);
	if (_data.empty()) {
	  reject(lock);
	}
	raw = _data.front().release();
	_data.pop_front();
  }

  return std::move(tbs::make_wrapper_guard<Type, PoolWrapper>(this, raw));
}

template<typename Type>
void Pool<Type>::release(Type &item) {
  tbs::sys_unique_lock lock(mutex_);
  Type *ptr = &item;
  if (_rf != nullptr) {
	ptr = _rf(ptr);
  }
  _data.push_back(u_ptr(ptr));
}

template<typename Type>
void Pool<Type>::reject(tbs::sys_unique_lock &lock) {
  condition_variable_.wait(lock, [this]() { return !_data.empty(); });
}

#undef INUSE_LOGGERS

static BuiltInLoggers::ConsoleLogger consoleLogger("CLOSED_POOL");
//static BuiltInLoggers::SimpleFileLogger simpleFileLogger("file", "log.txt");

#define INUSE_LOGGERS &consoleLogger

template<typename T>
ClosedPool<T>::~ClosedPool() {
  while (_in_used_num > 0) {
	std::this_thread::yield();
  }
}

template<typename T>
size_t ClosedPool<T>::in_used() const
noexcept {
return
_in_used_num;
}

template<typename T>
size_t ClosedPool<T>::size() const
noexcept {
return _q.
size();
}

template<typename T>
void ClosedPool<T>::cut_back(const size_t &s)
noexcept
{
tbs::sys_unique_lock l(_mutex);
while (s > 0 && !_q.
empty()
)
{
_q.
pop_back();
}
}

template<typename T>
void ClosedPool<T>::put(T &&val)
noexcept
{
tbs::sys_unique_lock l(_mutex);
_q.
push_back (std::make_unique<T>(std::forward<T>(val)));
}

template<typename T>
template<typename... ARGS, typename F>
void ClosedPool<T>::work_on(F &&f, ARGS... args)
noexcept
{
static_assert(std::is_invocable<F, T &, ARGS...>::value,
"F must be invocable with T& and ARGS...");
uptr ptr = nullptr;
{
tbs::sys_unique_lock s(_mutex);
WARN_LOG("wait for free item")
condition_variable_.
wait(s,
[this]() {
return !_q.
empty();
});
WARN_LOG("wait done for free item")
ptr = std::move(_q.front());
_q.
pop_front();
_in_used_num++;
}
try
{
f(*ptr, args
...);
}
catch (
tbs::base_error &e
)
{
ERROR_LOG("invoke a error {}", e.
what()
);
}
{
tbs::sys_unique_lock s(_mutex);
_q.
push_back(std::move(ptr)
);
_in_used_num--;
condition_variable_.
notify_one();
WARN_LOG("return back ")
}
}

#endif//TBS_CPP_POOL_CU
